import {Boot, IButtonMenu, IDomEditor,IModuleConf,IModalMenu,SlateDescendant,SlateElement,SlateNode, DomEditor} from '@wangeditor/editor'
import { h, VNode } from 'snabbdom'

// 自定义续写按钮功能
class ContinueButtonMenu implements IButtonMenu {
    constructor() {
        this.title = '续写' // 自定义菜单标题
        // this.iconSvg = '<svg>...</svg>' // 可选
        this.tag = 'button'
    }

    // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
    getValue(editor: IDomEditor): string | boolean {
        return false
    }

    // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
    isActive(editor: IDomEditor): boolean {
        return false
    }

    // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
    isDisabled(editor: IDomEditor): boolean {
        return false
    }

    // 点击菜单时触发的函数
    exec(editor: IDomEditor, value: string | boolean) {
        if (this.isDisabled(editor)) return
        editor.onContinue(editor)
        editor.blur()
    }
}

const continueButtonMenuConf = {
    key: 'continue', // 定义 menu key ：要保证唯一、不重复（重要）
    factory() {
        return new ContinueButtonMenu() // 把 `YourMenuClass` 替换为你菜单的 class
    },
}

// 自定义润色按钮功能
class PolishButtonMenu implements IButtonMenu {
    constructor() {
        this.title = '润色' // 自定义菜单标题
        // this.iconSvg = '<svg>...</svg>' // 可选
        this.tag = 'button'
    }

    // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
    getValue(editor: IDomEditor): string | boolean {
        return false
    }

    // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
    isActive(editor: IDomEditor): boolean {
        return false
    }

    // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
    isDisabled(editor: IDomEditor): boolean {
        return false
    }

    // 点击菜单时触发的函数
    exec(editor: IDomEditor, value: string | boolean) {
        if (this.isDisabled(editor)) return
        editor.onPolish(editor)
        editor.blur()

    }
}

const polishButtonMenuConf = {
    key: 'polish', // 定义 menu key ：要保证唯一、不重复（重要）
    factory() {
        return new PolishButtonMenu() // 把 `YourMenuClass` 替换为你菜单的 class
    },
}

// 自定义评论按钮功能
class CommentMenu implements IModalMenu {
    constructor() {
        this.title = '评论'
        // this.iconSvg = '<svg >...</svg>'
        this.tag = 'button'
        this.showModal = true
        this.modalWidth = 300
    }

    // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
    isActive(editor: IDomEditor): boolean {
        return false
    }

    // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
    getValue(editor: IDomEditor): string | boolean {
        return ''
    }

    // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
    isDisabled(editor: IDomEditor): boolean {
        return false
    }

    // 点击菜单时触发的函数
    exec(editor: IDomEditor, value: string | boolean) {
        // Modal menu ，这个函数不用写，空着即可
    }

    // 弹出框 modal 的定位：1. 返回某一个 SlateNode； 2. 返回 null （根据当前选区自动定位）
    getModalPositionNode(editor: IDomEditor): SlateNode | null {
        return null // modal 依据选区定位
    }

    // 定义 modal 内部的 DOM Element
    getModalContentElem(editor: IDomEditor): DOMElement {
        const $container = $('<div></div>')

        const inputId = `input-${Math.random().toString(16).slice(-8)}`
        const submitButtonId = `button-${Math.random().toString(16).slice(-8)}`
        const cancelButtonId = `button-${Math.random().toString(16).slice(-8)}`

        const $inputContainer = $(`<label class="babel-container">
            <span>评论</span>
            <textarea  id="${inputId}" ></textarea>
          </label>`)
        const $buttonContainer = $(`<div class="button-container" style="display: flex;justify-content: flex-end">
            <button id="${cancelButtonId}">取消</button>
            <button id="${submitButtonId}" style="margin-left: 20px">确定</button>
          </div>`)

        $container.append($inputContainer).append($buttonContainer)

        $container.on('click', `#${submitButtonId}`, e => {
            e.preventDefault()
            const text = $(`#${inputId}`).val()
            if (!text) return
            editor.onComment(editor,text)
            editor.hidePanelOrModal()
            editor.restoreSelection() // 恢复选区
        })
        $container.on('click', `#${cancelButtonId}`, e => {
            e.preventDefault()
            editor.restoreSelection() // 恢复选区
        })

        setTimeout(() => {
            $(`#${inputId}`).focus()
        })

        return $container[0]

        // PS：也可以把 $container 缓存下来，这样不用每次重复创建、重复绑定事件，优化性能
    }
}

const commentMenuConf = {
    key: 'comment', // 定义 menu key ：要保证唯一、不重复（重要）
    factory() {
        return new CommentMenu() // 把 `YourMenuClass` 替换为你菜单的 class
    },
}

function withComment<T extends IDomEditor>(editor: T) {
    // TS 语法
    // function withAttachment(editor) {                        // JS 语法
    const { isInline, isVoid } = editor
    const newEditor = editor

    newEditor.isInline = (elem) => {
        const type = DomEditor.getNodeType(elem)
        if (type === 'comment') return true // 针对 type: attachment ，设置为 inline
        return isInline(elem)
    }

    newEditor.isVoid = (elem) => {
        const type = DomEditor.getNodeType(elem)
        if (type === 'comment') return true // 针对 type: attachment ，设置为 void
        return isVoid(elem)
    }

    return newEditor // 返回 newEditor ，重要！！！
}

/**
 * 渲染“评论”元素到编辑器
 * @param elem 附件元素，即上文的 myResume
 * @param children 元素子节点，void 元素可忽略
 * @param editor 编辑器实例
 * @returns vnode 节点（通过 snabbdom.js 的 h 函数生成）
 */
function renderComment(elem: SlateElement, children: VNode[] | null, editor: IDomEditor): VNode {
    // 获取“附件”的数据，参考上文 myResume 数据结构
    const { id = '', commentTarget = '', bgColor = 'none' } = elem
    // 附件元素 vnode
    const attachVnode = h(
        // HTML tag
        'span',
        // HTML 属性、样式、事件
        {
            props: { contentEditable: true,id }, // HTML 属性，驼峰式写法
            style: { display: 'inline-block', backgroundColor: bgColor /* 其他... */ }, // style ，驼峰式写法
            // on: { click() { console.log('clicked', link) }, /* 其他... */ }
        },
        // 子节点
        [ commentTarget ]

    )
    return attachVnode
}

const renderElemConf = {
    type: 'comment', // 新元素 type ，重要！！！
    renderElem: renderComment,
}

/**
 * 生成“附件”元素的 HTML
 * @param elem 附件元素，即上文的 myResume
 * @param childrenHtml 子节点的 HTML 代码，void 元素可忽略
 * @returns “附件”元素的 HTML 字符串
 */
function commentToHtml(elem: SlateElement, childrenHtml: string): string {
    // TS 语法
    // function attachmentToHtml(elem, childrenHtml) {                             // JS 语法

    // 获取附件元素的数据
    const { id = '', commentContent = '', commentTarget='', bgColor='none' } = elem

    // 生成 HTML 代码
    const html = `<span
        data-w-e-type="comment"
        data-w-e-is-void
        data-w-e-is-inline
        data-id="${id}"
        data-bgColor="${bgColor}"
        data-commentContent="${commentContent}"
        data-commentTarget="${commentTarget}"
    >${commentTarget}</span>`

    return html
}

const elemToHtmlConf = {
    type: 'comment', // 新元素的 type ，重要！！！
    elemToHtml: commentToHtml,
}

/**
 * 解析 HTML 字符串，生成“附件”元素
 * @param domElem HTML 对应的 DOM Element
 * @param children 子节点
 * @param editor editor 实例
 * @returns “附件”元素，如上文的 myResume
 */
function parseCommentHtml(domElem: Element, children: SlateDescendant[], editor: IDomEditor): SlateElement {
    // TS 语法
    // function parseAttachmentHtml(domElem, children, editor) {                                                     // JS 语法

    // 从 DOM element 中获取“附件”的信息
    const id = domElem.getAttribute('data-id') || ''
    const commentContent = domElem.getAttribute('data-commentContent') || ''
    const commentTarget = domElem.getAttribute('data-commentTarget') || ''
    const bgColor = domElem.getAttribute('data-bgColor') || 'none'

    // 生成“附件”元素（按照此前约定的数据结构）
    const myResume = {
        type: 'comment',
        id,
        bgColor,
        commentContent,
        commentTarget,
        children: [{ text: '' }], // void node 必须有 children ，其中有一个空字符串，重要！！！
    }

    return myResume
}
const parseHtmlConf = {
    selector: 'span[data-w-e-type="comment"]', // CSS 选择器，匹配特定的 HTML 标签
    parseElemHtml: parseCommentHtml,
}

const module: Partial<IModuleConf> = {
    menus: [continueButtonMenuConf, polishButtonMenuConf,commentMenuConf],
    editorPlugin: withComment,
    renderElems: [renderElemConf /* 其他元素... */], // renderElem
    elemsToHtml: [elemToHtmlConf /* 其他元素... */], // elemToHtml
    parseElemsHtml: [parseHtmlConf /* 其他元素... */], // parseElemHtml
}
Boot.registerModule(module)